package com.ddwl.gate.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.ddwl.common.annotation.Auth;
import com.ddwl.common.constant.BaseEnum;
import com.ddwl.common.constant.GateEnum;
import com.ddwl.common.constant.RedisKey;
import com.ddwl.common.controller.BaseController;
import com.ddwl.common.service.RedisService;
import com.ddwl.gate.service.WechatService;
import com.ddwl.gate.util.wechat.AesException;
import com.ddwl.schema.bo.gate.GetWxcodeUnlimitBo;
import com.ddwl.schema.bo.gate.wechat.WxTemplateMsgBo;
import com.ddwl.schema.bo.gate.wechat.WxURLSchemeBo;
import com.ddwl.schema.vo.base.RestVo;
import com.ddwl.schema.vo.base.WxRestVo;
import com.ddwl.schema.vo.gate.wechat.WechatUserInfoListVo;
import com.ddwl.schema.vo.gate.wechat.WechatUserInfoVo;
import com.ddwl.schema.vo.gate.wechat.WxConfigVo;
import com.ddwl.schema.vo.gate.wechat.WxUserInfoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.xml.sax.SAXException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author Fu Zhaohui
 * @version 1.0.0.RELEASE
 * @date 2020/3/5 10:32 上午
 */
@Api(tags = "微信服务")
@RequestMapping("/wechat")
@RestController
@RequiredArgsConstructor
public class WechatController extends BaseController {

    private final WechatService wechatService;
    private final RedisService redisService;

    @GetMapping("/session/get")
    @ApiOperation("获得用户登录SessionKey")
    @Auth(required = false, product = {BaseEnum.ProductEnum.WBM, BaseEnum.ProductEnum.MALL})
    public RestVo<WxUserInfoVo> getSessionKey(@RequestParam String code, @RequestParam(required = false) String appId) {
        return RestVo.ok(wechatService.getSessionKey(code, appId, Optional.ofNullable(getProduct()).orElse(BaseEnum.ProductEnum.MALL.getName())));
    }

    @GetMapping("/config")
    @ApiOperation("获取微信公众号配置")
    @Auth(required = false, product = BaseEnum.ProductEnum.WBM_OFFICE)
    public RestVo<WxConfigVo> getConfig(@RequestParam String appId, @RequestParam(required = false) String url) {
        return RestVo.ok(wechatService.getConfig(appId, url));
    }

    @GetMapping("/wbm/session/get")
    @ApiOperation("五八马小程序获得用户登录SessionKey")
    @Auth(required = false, product = BaseEnum.ProductEnum.WBM)
    public RestVo<WxUserInfoVo> getWbmSessionKey(@RequestParam String code, @RequestParam String appId, @RequestParam(required = false) String inviteId) {
        return RestVo.ok(wechatService.getWbmSessionKey(code, appId, inviteId, getProduct(), getDk()));
    }

    @GetMapping("/oauth2")
    @ApiOperation("五八马公众号或App微信授权登录")
    @Auth(required = false, product = BaseEnum.ProductEnum.WBM_OFFICE)
    public RestVo<WxUserInfoVo> oauth2(@RequestParam String code, @RequestParam String appId) {
        return RestVo.ok(wechatService.oauth2(code, appId, getProduct()));
    }

    @PostMapping("/notify")
    @ApiOperation("开放平台微信通知")
    public void wxMsgNotify(HttpServletRequest request, HttpServletResponse response,
                            @RequestParam(required = false) String msg_signature,
                            @RequestParam(required = false) String signature,
                            @RequestParam(required = false) String timestamp,
                            @RequestParam(required = false) String nonce,
                            @RequestParam(required = false) String echostr) throws ParserConfigurationException, AesException, SAXException, IOException {

        PrintWriter printWriter = response.getWriter();
        if (StringUtils.hasText(echostr)) {
            String appId = "wx4c69e9c2c6ad0d03";
            printWriter.print(wechatService.verifyUrl(appId, Optional.ofNullable(signature).orElse(msg_signature), timestamp, nonce, echostr));
        } else {
            wechatService.handleMsg(null, request, msg_signature, timestamp, nonce);
            printWriter.print("success");
        }
        printWriter.flush();
        printWriter.close();
    }

    @RequestMapping("/{appId}/notify")
    @ApiOperation("微信后台通知")
    public void wxMsgNotify(HttpServletRequest request, HttpServletResponse response,
                            @PathVariable String appId,
                            @RequestParam(required = false) String msg_signature,
                            @RequestParam(required = false) String signature,
                            @RequestParam(required = false) String timestamp,
                            @RequestParam(required = false) String nonce,
                            @RequestParam(required = false) String echostr) throws ParserConfigurationException, AesException, SAXException, IOException {

        PrintWriter printWriter = response.getWriter();
        if (StringUtils.hasText(echostr)) {
            printWriter.print(echostr);
//            printWriter.print(wechatService.verifyUrl(appId, signature, timestamp, nonce, echostr));
        } else {
            wechatService.handleMsg(appId, request, msg_signature, timestamp, nonce);
            printWriter.print("success");
        }
        printWriter.flush();
        printWriter.close();
    }

    @GetMapping("/auth/pre")
    @ApiOperation("获取微信预授权码")
    public RestVo preAuth(@RequestParam(required = false) String component_appid) {
        return RestVo.ok(wechatService.getPreAuthCode(component_appid));
    }

    @PostMapping("/auth/grant")
    @ApiOperation("微信授权回调")
    public RestVo grantAuth(@RequestParam(required = false) String component_appid,
                            @RequestParam String authorization_code,
                            @RequestParam String mchId) {
        wechatService.grantAuth(component_appid, authorization_code, mchId);
        return RestVo.ok();
    }

    @GetMapping("/auth/{appId}/get")
    @Auth(required = false, product = BaseEnum.ProductEnum.ZHENYU)
    @ApiOperation("微信授权帐号信息")
    public RestVo authInfo(@PathVariable String appId) {
        return RestVo.ok(wechatService.getAuthInfo(appId));
    }

    @PostMapping("/appcode/unlimit/create")
    @Auth(product = {BaseEnum.ProductEnum.MALL, BaseEnum.ProductEnum.FENXIAO, BaseEnum.ProductEnum.WBM, BaseEnum.ProductEnum.WBM_OFFICE})
    @ApiOperation("创建无限小程序码")
    public RestVo<String> createUlimitAppCode(@RequestBody GetWxcodeUnlimitBo body,
                                              @RequestParam(required = false) String shopId,
                                              @RequestParam(required = false) String itemId) {
        String appId = BaseEnum.WxAppId.WBM.getCode();
        if (!StringUtils.hasText(body.getScene())) {
            Map<String, String> sceneMap = new HashMap<>(3);
            if (StringUtils.hasText(shopId)) {
                sceneMap.put("shopId", shopId);
            }
            if(StringUtils.hasText(itemId)) {
                sceneMap.put("itemId", itemId);
            }
            if(sceneMap.isEmpty()) {
                body.setScene(getUserId());
            } else {
                sceneMap.put("userId", getUserId());
                String uuid = RandomUtil.randomString(32);
                redisService.getHashOps().putAll(RedisKey.SHARE_CODE_INFO.getKey(uuid), sceneMap);
                body.setScene(uuid);
            }
        }
        return RestVo.ok(Base64.encodeBase64String(wechatService.unlimitAppCode(body, appId)));
    }

    @GetMapping("/wxaCodeUnlimit/get")
    @ApiOperation("获取无限小程序码")
    RestVo<String> wxaCodeUnlimit(@RequestParam String param,
                                  @RequestParam String appId,
                                  @RequestParam String filePath,
                                  @ApiParam("跳转地址") @RequestParam(required = false) String page) {
        GetWxcodeUnlimitBo body = new GetWxcodeUnlimitBo();
        body.setScene(param);
        body.setPage(Optional.ofNullable(page).orElse(GateEnum.WbmMinAppPage.SHOP_INDEX.getPath()));
        return RestVo.ok(wechatService.wxaCodeUnlimitUrl(body, appId, filePath));
    }

    /**
     * @param param
     * @param appId
     * @param filePath
     * @param fileName logo文件在oss上的名称 带上自定义的名称  例：如过文件完整路径为 https://58d.oss-cn-hangzhou.aliyuncs.com/shop/wxaCodeUnlimit/hmjWxcode.png 则传参为：shop/wxaCodeUnlimit/hmjWxcode.png
     * @param page
     * @return
     */
    @GetMapping("/wxaCodeUnlimit/customizeLogo")
    @Auth(product = BaseEnum.ProductEnum.API)
    @ApiOperation("自定义logo小程序码")
    RestVo<String> customizeLogoWxaCodeUrl(@RequestParam String param,
                                           @RequestParam String appId,
                                           @RequestParam String filePath,
                                           @RequestParam String fileName,
                                           @ApiParam("跳转地址") @RequestParam(required = false) String page) {
        GetWxcodeUnlimitBo body = new GetWxcodeUnlimitBo();
        body.setScene(param);
        body.setPage(Optional.ofNullable(page).orElse(GateEnum.WbmMinAppPage.SHOP_INDEX.getPath()));
        return RestVo.ok(wechatService.customizeLogoWxaCodeUrl(body, appId, filePath, fileName, 195, 195));
    }

    /**
     * 获取店铺小程序码
     *
     * @param param
     * @param appId
     * @return
     */
    @GetMapping("/shopWxaCode/get")
    @Auth(product = BaseEnum.ProductEnum.API)
    @ApiOperation("店铺小程序码")
    RestVo<String> getShopWxaCode(@RequestParam String param, @RequestParam String appId, @RequestParam(required = false) String fileName) {
        GetWxcodeUnlimitBo body = new GetWxcodeUnlimitBo();
        body.setScene(param);
        body.setWidth(671);
        body.setPage(GateEnum.WbmMinAppPage.SHOP_INDEX.getPath());
        return RestVo.ok(wechatService.getShopWxaCode(body, appId, fileName, 320, 320));
    }

    /**
     * 用户分享码
     *
     * @param param
     * @param appId
     * @return
     */
    @PostMapping("/userShareCode/get")
    @Auth(product = BaseEnum.ProductEnum.API)
    @ApiOperation("获取用户分享码")
    public RestVo<String> getUserShareCode(@RequestParam String param, @RequestParam String appId) {
        GetWxcodeUnlimitBo body = new GetWxcodeUnlimitBo();
        body.setScene(param);
        body.setPage(GateEnum.WbmMinAppPage.SHOP_INDEX.getPath());
        return RestVo.ok(wechatService.getUserShareCode(body, appId));
    }

    /**
     * 生成 小程序urlscheme
     *
     * @return
     */
    @PostMapping("/generateScheme")
    @ApiOperation("生成小程序url scheme码")
    @Auth(product = BaseEnum.ProductEnum.API)
    public RestVo<String> generateScheme(@RequestParam String appId, @RequestParam String path, @RequestParam(required = false) String query, @RequestParam(required = false) Boolean is_expire, @RequestParam(required = false) long expire_time) {
        WxURLSchemeBo bo = new WxURLSchemeBo();
        WxURLSchemeBo.JumpWxa jumpWxa = new WxURLSchemeBo.JumpWxa();
        jumpWxa.setPath(path);
        if (StrUtil.isNotEmpty(query)) {
            jumpWxa.setQuery(query);
        } else {
            jumpWxa.setQuery("");
        }
        bo.setJump_wxa(jumpWxa);
        bo.set_expire(null == is_expire ? false : is_expire);
        bo.setExpire_time(expire_time);
        return RestVo.ok(wechatService.generateScheme(appId, bo));
    }

    @PostMapping("/tempMessagePush")
    @ApiOperation("推送微信模板消息")
    @Auth(product = BaseEnum.ProductEnum.API)
    public RestVo<WxRestVo> tempMessagePush(@RequestBody WxTemplateMsgBo template) {
        return RestVo.ok(wechatService.tempMessagePush(template));
    }

    @GetMapping("/batchGetWxUserInfo")
    @ApiOperation("批量获取微信公众号用户信息")
    @Auth(product = BaseEnum.ProductEnum.API)
    public RestVo<WechatUserInfoListVo> batchGetWxUserInfo(@RequestParam(required = false) String nextOpenId) {
        return RestVo.ok(wechatService.batchGetWxUserInfo(nextOpenId));
    }

    @GetMapping("/getWechatUserInfo")
    @ApiOperation("获取微信公众号用户信息")
    @Auth(product = BaseEnum.ProductEnum.API)
    public RestVo<WechatUserInfoVo> getWechatUserInfo(@RequestParam() String openId) {
        return RestVo.ok(wechatService.getWechatUserInfo(openId));
    }

    @GetMapping("/getOSSBase64")
    @ApiOperation("获取oss文件流")
    @Auth(product = BaseEnum.ProductEnum.API)
    public RestVo<String> getOSSBase64(@RequestParam() String fileName) {
        return RestVo.ok(wechatService.getOSSBase64(fileName));
    }

}
